﻿using Basic.WxApiRemoteModel;
using Basic.WxApiRemoteModel.WxBind.Model;
using Basic.WxApiService.Interface;
using Basic.WxExtendService.Interface;
using Basic.WxService.Interface;
using Basic.WxService.Model;
using Basic.WxService.Model.WxBind;
using WeDonekRpc.CacheClient.Interface;
using WeDonekRpc.Client.Attr;
using WeDonekRpc.Helper;
using WeDonekRpc.Model;

namespace Basic.WxService.ApiService
{
    [ClassLifetimeAttr(ClassLifetimeType.SingleInstance)]
    internal class WxBindStateService : IWxBindStateService
    {
        private static readonly string _CacheKey = "WxBindApply_";
        private readonly IRedisCache _Redis;

        private readonly IWxConfig _Config;

        public WxBindStateService (IRedisCache redis,
            IWxPlatformService platform,
            IWxConfig config)
        {
            this._Redis = redis;
            this._Config = config;
        }

        public string ApplyBind (ApplyBindArg obj, MsgSource source)
        {
            string appId = obj.PlatformAppId.IsNull(this._Config.DefPlatformAppId);
            WxMerBindCache add = new WxMerBindCache
            {
                ApplyId = Guid.NewGuid().ToString("N"),
                BindStatus = WxBindStatus.初始化,
                ReplySet = new RpcReplySet(obj.ReplySet, source),
                AuthType = obj.BindType,
                CallbackUri = obj.CallbackUri,
                AppId = appId
            };
            string key = _CacheKey + add.ApplyId;
            if (!this._Redis.Add(key, add, new TimeSpan(0, 0, this._Config.ApplyOverTime)))
            {
                throw new ErrorException("wx.bind.apply.add.fail");
            }
            return add.ApplyId;
        }
        public WxMerBindCache Get (string applyId)
        {
            string key = _CacheKey + applyId;
            if (!this._Redis.TryGet(key, out WxMerBindCache apply))
            {
                throw new ErrorException("wx.apply.overtime");
            }
            return apply;
        }
        public WxMerBindCache Begin (string preauthCode, string wxAppId)
        {
            string key = "WxPreauth_" + preauthCode.GetMd5().ToLower();
            if (!this._Redis.TryRemove(key, out string applyId))
            {
                return null;
            }
            WxMerBindCache apply = this.Get(applyId);
            if (apply.BindStatus != WxBindStatus.待绑定)
            {
                return null;
            }
            apply.WxAppId = wxAppId;
            apply.BindStatus = WxBindStatus.数据同步中;
            this.Save(apply);
            return apply;
        }
        public void Complete (WxMerBindCache apply)
        {
            apply.BindStatus = WxBindStatus.绑定完成;
            this.Save(apply);
        }
        public void Fail (WxMerBindCache apply, string error)
        {
            apply.BindStatus = WxBindStatus.绑定失败;
            apply.Error = error;
            this.Save(apply);
        }
        public void Save (WxMerBindCache apply)
        {
            string key = _CacheKey + apply.ApplyId;
            TimeSpan time = apply.OverTime.Value - DateTime.Now;
            _ = this._Redis.Set(key, apply, time);
            if (apply.BindStatus == WxBindStatus.待绑定)
            {
                key = "WxPreauth_" + apply.PreauthCode.GetMd5().ToLower();
                _ = this._Redis.Add(key, apply.ApplyId, time);
            }
        }
    }
}
